<template>
  <div ref="graphContainer" class="graph-container flow-detail">
    <div class="layout" :class="loading ? 'loading' : ''">
      <!-- 图形容器 -->
      <div :id="id" :ref="id" class="graph-main-container" />
    </div>
  </div>
</template>

<script>
import { FunctionExt } from '@antv/x6';
import registerNode from './shape/registerNode';
import { initGraph } from './common/graph';

import * as graphFunc from './common/functions';
import { Scroller } from '@antv/x6-plugin-scroller';

export default {
  name: 'AvicBpmFlowCanvas',
  props: {
    flowId: {
      type: String,
      default: '8a69d6f87db1d421017db6b8d5b807e3'
    },
    data: {
      type: Object,
      required: true
    },
    flowType: {
      // 1未发布,2已发布
      type: Number,
      default: 2
    },
    flowQueryUrl: {
      type: Object,
      default: () => ({
        get: '/api/bpm/design/getProcessJson/v1'
      })
    },
    // 画布初始化自定义选项 可覆盖graph.js中的默认值
    graphOption: {
      type: Object,
      default: () => ({})
    }
  },
  data() {
    return {
      id: '',
      formData: {},
      graph: {},
      node: [],
      graphKey: '',
      disabled: false,
      currentIndex: 0,
      selectCell: '',
      nodeForm: {},
      type: 'grid',
      grid: {
        size: 10, // 网格大小 10px
        visible: true, // 渲染网格背景
        type: 'mesh',
        args: {
          color: '#D0D0D0',
          thickness: 1, // 网格线宽度/网格点大小
          factor: 10
        }
      },
      isRending: false,
      tooltipsContent: null,
      loading: true
    };
  },
  created() {
    this.id = `container${this.getRandomAlphaNum(10)}`;
  },
  mounted() {
    this.initFlow(this.data);
  },
  methods: {
    calcGrphSize() {
      const { edge, node } = this.data;
      const points = [];
      edge?.forEach((item) => {
        if (!item.vertices?.length) return;
        points.push(...item.vertices);
      });
      node?.forEach((item) => {
        points.push(item.position);
        // 所有节点默认尺寸
        let width = 40;
        let height = 40;
        // 人工节点尺寸
        if (item.data.nodeType === 'task') {
          width = 132;
          height = 72;
        } else if (item.data.nodeType === 'text') {
          // 文本框节点尺寸
          width = item.size?.width;
          height = item.size?.height;
        }
        points.push({ x: item.position.x + width, y: item.position.y + height });
      });
      let minx = points[0]?.x || 0;
      let miny = points[0]?.y || 0;
      let maxx = points[0]?.x || 0;
      let maxy = points[0]?.y || 0;
      points.forEach((item) => {
        if (item.x < minx) {
          minx = item.x;
        }
        if (item.y < miny) {
          miny = item.y;
        }
        if (item.x > maxx) {
          maxx = item.x;
        }
        if (item.y > maxy) {
          maxy = item.y;
        }
      });
      edge?.forEach((item) => {
        item.vertices?.forEach((vts) => {
          vts.x = vts.x - minx + 16;
          vts.y = vts.y - miny + 32;
        });
      });
      node?.forEach((item) => {
        item.position.x = item.position.x - minx + 16;
        item.position.y = item.position.y - miny + 32;
      });
      return { width: maxx - minx + 32, height: maxy - miny + 64 };
    },
    // eslint-disable-next-line consistent-return
    initMain(fn) {
      if (this.graph && this.graph.data) {
        if (fn) {
          return fn();
        }
      }
      window.setTimeout(() => {
        // 实例化x6
        this.graph = initGraph(this.id, {
          ...this.graphOption,
          ...this.calcGrphSize()
        });

        this.graph.use(
          new Scroller({
            enabled: true,
            pageVisible: false,
            pageBreak: true,
            pannable: false,
            className: 'flow-instance-scroller',
            padding: 0,
            // width: graphContainerWidth,
            // height: graphContainerHeight,
            pageWidth: 180,
            pageHeight: 78
          })
        );

        // 监听
        this.initListenerCustomEvent();
        graphFunc.onlyLook(true, this.graph);

        // 注册节点
        registerNode();

        fn && fn();
        setTimeout(() => {
          this.$nextTick(() => {
            graphFunc.onlyLook(true, this.graph);
            this.graph.positionPoint({ x: 0, y: 0 }, 16, 16);
            this.$nextTick(() => {
              this.loading = false;
            });
          });
        }, 100);
        return true;
      }, 300);
    },
    initFlow(data) {
      this.loading = true;
      if (Object.keys(data).length > 0 && !this.isRending) {
        this.isRending = true;
        // eslint-disable-next-line consistent-return
        this.initMain(() => {
          const { edge, graph, node } = data;
          if (!graph.key) return this.$message.error('获取参数错误,缺少key');
          this.graphKey = graph.key;

          if (this.graph && this.graph.data) {
            // 自由流程 暂存后 流程图不刷新
            graphFunc.initDefaultData(node, edge, this.graph);
            return false;
          }

          this.graph.data = graph.data;
          graphFunc.initDefaultData(node, edge, this.graph);
        });
      }
    },
    // top:start节点以上50左50定位，middle：start节点已画布中心定位，默认：画布居中
    setStartPosition(pos) {
      this.resizeGraph();
      if (!this.graph.getNodes) return;
      if (pos === 'middle') {
        this.graph.positionPoint({ x: 0, y: 0 });
      } else if (pos !== 'top') {
        this.graph.center();
      }
    },
    resizeGraph() {
      const graphDiv = this.$refs[this.id];

      const paddingBtm = 50;

      const graphDivW = graphDiv.style.width;
      const graphDivH = graphDiv.style.height;

      // 容器父级
      const parentL1 = graphDiv.parentNode;
      // 滚动容器祖父级
      const parentL2 = graphDiv.parentNode.parentNode;
      graphDiv.style.height = `${parseInt(graphDivH) + paddingBtm}px`;

      graphDiv.style.width = `${parseInt(graphDivW) - 0}px`;
      graphDiv.style.left = `${0}px`;
      graphDiv.style.top = `${0}px`;

      parentL1.style.width = `${parseInt(graphDivW) - 0}px`;
      parentL1.style.height = `${parseInt(graphDivH) + paddingBtm}px`;

      parentL2.style.width = graphDivW;
      parentL2.style.height = `${parseInt(graphDivH) + paddingBtm}px`;
      parentL2.style.overflow = 'hidden';
      parentL2.style.overflowX = 'auto';
    },
    lockCanvas(status = true) {
      graphFunc.onlyLook(status, this.graph);
    },
    initListenerCustomEvent() {
      // emit 节点单击
      this.graph.on('node:click', ({ e, x, y, node, view }) => {
        if (e.target && e.target.id === 'user-defined') {
          this.$emit('user-defined-click', { e, x, y, node, view });
        } else {
          this.$emit('node-click', { e, x, y, node, view });
        }
      });
      // 节点鼠标移入
      this.graph.on(
        'node:mouseenter',
        FunctionExt.debounce(({ e, node, view }) => {
          this.$emit('node-mouseenter', { e, node, view });
        }),
        500
      );
      // 节点鼠标移出
      this.graph.on('node:mouseleave', ({ e, node, view }) => {
        this.$emit('node-mouseleave', { e, node, view });
      });
    },
    getRandomAlphaNum(len) {
      let rdmString = '';
      for (; rdmString.length < len; rdmString += Math.random().toString(36));
      return rdmString.substr(0, len);
    }
  }
};
</script>

<style lang="less" scoped>
.graph-container {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  .toolbar-container {
    position: absolute;
    top: 60px;
    right: 330px;
    z-index: 999;
    width: 400px;
    height: 30px;
    background-color: #fff;
    border-radius: 3px;
    box-shadow: 0px 1px 8px -2px #000;
  }
}

.layout {
  position: relative;
  box-sizing: border-box;
  width: 100%;
  height: 100%;
  padding: 0;
  &.loading {
    opacity: 0;
  }

  .graph-main-container {
    width: 100%;
    height: calc(100% - 8px);
  }

  // tooltip
  #tooltip-container {
    position: absolute;
    z-index: 1;
    display: none;
    display: n;
    width: 350px;
    padding: 10px;
    color: #545454;
    font-size: 12px;
    word-break: break-all;
    background-color: rgba(255, 255, 255, 0.9);
    border: 1px solid #e2e2e2;
    border-radius: 4px;
    box-shadow: rgb(174, 174, 174) 0px 0px 10px;
    user-select: none;
  }
  .node-bar-container {
    z-index: 2;
  }
  .panel-area-container {
    top: 0;
    right: 0;
    z-index: 2;
    height: 100%;
    box-shadow: 0 0 10px 0px #0000003b;
  }
}

// 连接点交互
circle[data-class='choice-point']:hover {
  transition: all 0.05s;
}
.options-container {
  position: absolute;
  z-index: 2;
  width: 100%;
  height: 50px;
  padding: 0 10px;
  padding-top: 13px;
  padding-right: 330px;
  padding-left: 60px;
  text-align: right;
  background: #fff;
  border-bottom: 1px solid #efefef;
  button {
    margin: 0 5px;
  }
}
</style>
<style lang="less" scoped>
:deep(.x6-node) {
  overflow: visible;
  [magnet='true'] {
    cursor: crosshair;
    transition: none;

    &[port-group='in'] {
      cursor: move;
    }
  }

  &.x6-node-immovable {
    cursor: pointer;
  }

  .x6-port-body {
    visibility: hidden;
  }

  foreignObject {
    body {
      min-width: auto;
      // &.user-defined-border {
      //   border: 1px solid #0e42d2;
      //   padding: 10px;
      //   // 适配132*72节点尺寸
      //   width: 152px !important;
      //   height: 92px !important;
      //   margin: -10px;
      // }
      &.jump-start-node {
        border: 3px solid #1e89ff;
        border-radius: 4px;
        padding: 20px;
        padding-top: 30px;
        // 适配132*72节点尺寸
        width: 180px !important;
        height: 127px !important;
        margin: -15px;
        margin-left: -23px;
        margin-top: -33px;
      }
    }
  }
}
</style>
